package com.iot.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.iot.commons.ResponseResult;
import com.iot.enums.StatusEnum;
import com.iot.mapper.DeviceDataStepsMapper;
import com.iot.model.entity.DeviceDataStepsEntity;
import com.iot.model.query.DeviceDataStepsQuery;
import com.iot.model.dto.DeviceDataStepsDto;
import com.iot.model.query.FollowQuery;
import com.iot.model.vo.AuthInfoVo;
import com.iot.model.vo.DeviceDataStepsVo;
import com.iot.service.DeviceDataStepsService;
import com.iot.utils.DateUtil;
import com.iot.utils.ResponseResultUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * DeviceDataStepsServiceImpl
 *
 * @author: dh
 * @date: 2024-04-21 10:52:03
 */
@Service
@RequiredArgsConstructor
public class DeviceDataStepsServiceImpl implements DeviceDataStepsService {

    private final DeviceDataStepsMapper deviceDataStepsMapper;

    @Override
    public ResponseResult getList(DeviceDataStepsQuery deviceDataSteps) {
        AuthInfoVo authInfoEntity = (AuthInfoVo) StpUtil.getSession().get("loginInfo");
        if (null == authInfoEntity) {
            return ResponseResultUtil.authInfoFailure();
        }
        Page<DeviceDataStepsEntity> page = new Page<>(deviceDataSteps.getPageIndex(), deviceDataSteps.getPageSize());
        LambdaQueryWrapper<DeviceDataStepsEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(DeviceDataStepsEntity::getAuthId, authInfoEntity.getId());
        queryWrapper.eq(DeviceDataStepsEntity::getState, StatusEnum.VALID.getKey());

        if (null != deviceDataSteps.getStartTime()) {
            queryWrapper.ge(DeviceDataStepsEntity::getTime, deviceDataSteps.getStartTime());
        }
        if (null != deviceDataSteps.getEndTime()) {
            queryWrapper.le(DeviceDataStepsEntity::getTime, deviceDataSteps.getEndTime());
        }
        queryWrapper.orderByDesc(DeviceDataStepsEntity::getTime);
        IPage<DeviceDataStepsEntity> deviceDataStepsPage = deviceDataStepsMapper.selectPage(page, queryWrapper);
        List<DeviceDataStepsVo> deviceDataStepsVoList = Lists.newArrayList();
        for (DeviceDataStepsEntity deviceDataStepsEntity : deviceDataStepsPage.getRecords()) {
            DeviceDataStepsVo vo = new DeviceDataStepsVo();
            vo.setTime(deviceDataStepsEntity.getTime());
            vo.setStep(deviceDataStepsEntity.getStep());
            vo.setDuration(deviceDataStepsEntity.getDuration());
            vo.setCalorie(deviceDataStepsEntity.getCalorie());
            vo.setDistance(deviceDataStepsEntity.getDistance());
            deviceDataStepsVoList.add(vo);
        }

        return ResponseResultUtil.success(deviceDataStepsPage.getTotal(), deviceDataStepsVoList);
    }

    @Override
    public ResponseResult edit(DeviceDataStepsDto deviceDataSteps) {
        DeviceDataStepsEntity entity = new DeviceDataStepsEntity();
        entity.setId(deviceDataSteps.getId());
        entity.setTime(deviceDataSteps.getTime());
        entity.setStep(deviceDataSteps.getStep());
        entity.setDuration(deviceDataSteps.getDuration());
        entity.setCalorie(deviceDataSteps.getCalorie());
        entity.setDistance(deviceDataSteps.getDistance());
        entity.setState(deviceDataSteps.getState());
        entity.setCreateTime(deviceDataSteps.getCreateTime());
        deviceDataStepsMapper.updateById(entity);
        return ResponseResultUtil.success();
    }

    @Override
    public ResponseResult upload(List<DeviceDataStepsDto> deviceDataSteps,Long authId) {
        if (CollectionUtils.isEmpty(deviceDataSteps)) {
            return ResponseResultUtil.success();
        }
        if (null == authId) {
            return ResponseResultUtil.authInfoFailure();
        }
        List<DeviceDataStepsDto> newList = Lists.newArrayList();
        deviceDataSteps.stream().filter(distinctByKey(DeviceDataStepsDto::getTime))  //filter保留true的值
                .forEach(newList::add);

        List<Long> timeList = newList.stream().map(DeviceDataStepsDto::getTime).collect(Collectors.toList());

        LambdaQueryWrapper<DeviceDataStepsEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(DeviceDataStepsEntity::getAuthId, authId);
        queryWrapper.in(DeviceDataStepsEntity::getTime, timeList);
        List<DeviceDataStepsEntity> timeEntityList = deviceDataStepsMapper.selectList(queryWrapper);
        Map<Long, DeviceDataStepsEntity> groupByTime = Maps.newHashMap();
        if (CollectionUtils.isNotEmpty(timeEntityList)) {
            groupByTime =  timeEntityList.stream().collect(Collectors.toMap(DeviceDataStepsEntity::getTime,x->x,(obj1,obj2) -> obj2));
        }


        List<DeviceDataStepsEntity> entityList = Lists.newArrayList();
        for (DeviceDataStepsDto deviceDataStep : newList) {
            Long time = deviceDataStep.getTime();
            if (null == time || null == deviceDataStep.getStep()) {
                return ResponseResultUtil.paramFailure();
            }
            DeviceDataStepsEntity deviceDataStepsEntity = groupByTime.get(time);
            if (null != deviceDataStepsEntity) {
                continue;
            }
            DeviceDataStepsEntity entity = new DeviceDataStepsEntity();
            entity.setAuthId(authId);
            entity.setTime(time);
            entity.setStep(deviceDataStep.getStep());
            entity.setDuration(deviceDataStep.getDuration());
            entity.setCalorie(deviceDataStep.getCalorie());
            entity.setDistance(deviceDataStep.getDistance());
            entity.setState(StatusEnum.VALID.getKey());
            entity.setCreateTime(DateUtil.now());
            entityList.add(entity);
        }
        if (CollectionUtils.isNotEmpty(entityList)) {
            deviceDataStepsMapper.insertList(entityList);
        }
        return ResponseResultUtil.success();
    }

    static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = Maps.newConcurrentMap();
        //putIfAbsent方法添加键值对，如果map集合中没有该key对应的值，则直接添加，并返回null，如果已经存在对应的值，则依旧为原来的值。
        //如果返回null表示添加数据成功(不重复)，不重复(null==null :TRUE)
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    @Override
    public ResponseResult getById(DeviceDataStepsQuery deviceDataSteps) {
        DeviceDataStepsEntity deviceDataStepsEntity = deviceDataStepsMapper.selectById(deviceDataSteps.getId());
        DeviceDataStepsVo vo = new DeviceDataStepsVo();
        vo.setTime(deviceDataStepsEntity.getTime());
        vo.setStep(deviceDataStepsEntity.getStep());
        vo.setDuration(deviceDataStepsEntity.getDuration());
        vo.setCalorie(deviceDataStepsEntity.getCalorie());
        vo.setDistance(deviceDataStepsEntity.getDistance());
        return ResponseResultUtil.success(vo);
    }

    @Override
    public IPage<DeviceDataStepsEntity> getByDate(FollowQuery follow, Long followAuthId) {
        Page<DeviceDataStepsEntity> page = new Page<>(follow.getPageIndex(), follow.getPageSize());
        LambdaQueryWrapper<DeviceDataStepsEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(DeviceDataStepsEntity::getAuthId, followAuthId);
        queryWrapper.ge(DeviceDataStepsEntity::getTime, follow.getStartTime());
        if (null != follow.getEndTime()) {
            queryWrapper.le(DeviceDataStepsEntity::getTime, follow.getEndTime());
        }
        queryWrapper.orderByDesc(DeviceDataStepsEntity::getTime);
        return deviceDataStepsMapper.selectPage(page, queryWrapper);
    }
}
